﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevComponents.AdvTree;
using System.Xml;
using PlanningGIS.Win.Controls;
using PlanningGIS.Util.Serialization;
using PlanningGIS.ManageUtility.Modules;
using PlanningGIS.ManageUtility;
using PlanningGIS.Util.Regular;
using ESRI.ArcGIS.Geodatabase;
using PlanningGIS.Util.Log;
using PlanningGIS.ArcGIS;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using PlanningGIS.Util.Data;

namespace PlanningGIS.Framework.Controls
{
    /// <summary>
    /// 资源树
    /// </summary>
    public partial class ResourceTree : AdvTree
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public ResourceTree()
        {
            InitializeComponent();
            //SetStyle(System.Windows.Forms.ControlStyles.AllPaintingInWmPaint | System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer |
            //     System.Windows.Forms.ControlStyles.ResizeRedraw | System.Windows.Forms.ControlStyles.UserPaint, true);
        }

        /// <summary>
        /// 所有的资源节点
        /// </summary>
        private List<ResourceInfo> _Resources = null;

        /// <summary>
        /// 
        /// </summary>
        private List<Role_Rel> _RoleRels = null;

        /// <summary>
        /// 资源信息是否有改变
        /// </summary>
        private bool _IsChange = false;

        /// <summary>
        /// 是否显示复选框
        /// </summary>
        private bool _ShowCheckBox = true;

        /// <summary>
        /// 资源信息是否有改变
        /// </summary>
        public bool IsChange
        {
            get { return _IsChange; }
        }

        /// <summary>
        /// 是否显示复选框
        /// </summary>
        public bool ShowCheckBox
        {
            get
            {
                return _ShowCheckBox;
            }
            set
            {
                _ShowCheckBox = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        [Browsable(false)]
        public IMapControl2 MapControl { get; set; }

        /// <summary>
        /// 是否同时选中父节点与子节点
        /// </summary>
        public bool CheckWithin { get; set; }

        /// <summary>
        /// 重载资源选择事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnAfterCheck(AdvTreeCellEventArgs e)
        {
            if (e.Action != eTreeAction.Mouse) return;
            _IsChange = true;
            base.OnAfterCheck(e);
            if (CheckWithin) 
            {
                SetChildChecked(SelectedNode, e.Cell.Checked);
                if (SelectedNode.Parent != null)
                    SetParentCheck(SelectedNode.Parent);
            }
            if (MapControl != null)
            {
                LoadData(SelectedNode);
            }
        }
       
        /// <summary>
        /// 设置子节点的选中状态
        /// </summary>
        /// <param name="node">节点</param>
        /// <param name="isCheck">选中状态</param>
        private void SetChildChecked(Node node, bool isCheck)
        {
            if (node.Nodes.Count > 0)
            {
                foreach (Node itm in node.Nodes)
                {
                    itm.Checked = isCheck;
                    SetChildChecked(itm, isCheck);
                }
            }
        }

        /// <summary>
        /// 设置父节点状态
        /// </summary>
        /// <param name="treeNode">节点</param>
        private void SetParentCheck(Node treeNode)
        {
            bool isChecked = false;
            bool unChecked = false;
            bool twoChecked = false;
            foreach (DevComponents.AdvTree.Node node in treeNode.Nodes)
            {                
                if (node.CheckState == CheckState.Checked) isChecked = true;
                else if (node.CheckState == CheckState.Unchecked) unChecked = true;
                else twoChecked = true;
            }
            if (twoChecked) treeNode.CheckState = CheckState.Indeterminate;
            else if (isChecked && unChecked) treeNode.CheckState = CheckState.Indeterminate;
            else if (isChecked && (!unChecked && !twoChecked)) treeNode.CheckState = CheckState.Checked;
            else treeNode.CheckState = CheckState.Unchecked;
            if (treeNode.Parent != null)
            {
                SetParentCheck(treeNode.Parent);
            }
        }
        
        /// <summary>
        /// 重置控件
        /// </summary>
        public void ResetControl()
        {
            _IsChange = false;
        }

        /// <summary>
        /// 开始加载时绑定数据，并设定初始的选择状态
        /// </summary>
        /// <param name="remove">是否移除没有启用的资源</param>
        /// <param name="rels">用权限的数据资源</param>
        public void BindData(bool remove = false, List<Role_Rel> rels = null)   
        {
            this.Nodes.Clear();
            try
            {
                //if (AppConfig.IsRunLocal) return;
                _RoleRels = rels;
                _Resources = ManageHelper.DBContext.GetAllEntry<ResourceInfo>();
                if (_Resources == null || _Resources.Count == 0) return;
                AddChildNode("", null, remove);
                //this.ExpandAll();
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorText("获取资源列表失败，可能是维护库连接失败！");
                //LogHelper.WriteErrLog(ex.ToString());
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        private bool HasPrivilege(string id)
        {
            if (_RoleRels == null || _RoleRels.Count == 0) return true;
            Role_Rel rr = _RoleRels.Find(t => t.RelID.Equals(id, StringComparison.CurrentCultureIgnoreCase));
            if (rr == null) return false;
            return true;
        }
        
        /// <summary>
        /// 根据父节点添加对应的子节点
        /// </summary>
        /// <param name="parentid">父节点编号</param>
        /// <param name="parentnode">父节点</param>
        private void AddChildNode(string parentid, Node parentnode, bool remove = false)
        {
            List<ResourceInfo> nds = _Resources.FindAll(t => parentid.Equals(t.Parent_ID, StringComparison.CurrentCultureIgnoreCase)
                || (string.IsNullOrWhiteSpace(parentid) && string.IsNullOrWhiteSpace(t.Parent_ID))).OrderByDescending(t => t.ResType).ToList();
            if (nds == null || nds.Count == 0) return;
            foreach (ResourceInfo d in nds)
            {
                if (remove && !d.GetEnable()) continue;
                if (!HasPrivilege(d.ID)) continue;
                bool drag = true;
                if (d.ResType == ((int)zjgisResType.Dataset).ToString() ||
                    d.ResType == ((int)zjgisResType.FeatureClass).ToString()||
                    d.ResType == ((int)zjgisResType.GISDB).ToString())
                    drag = false;
                Node n = AddResNode(d, parentnode, drag);                
                if (n == null) continue;
                AddChildNode(d.ID, n, remove);                
            }
        }

        /// <summary>
        /// 在指定的节点上添加节点
        /// </summary>
        /// <param name="node">要添加的资源节点</param>
        /// <param name="parentNode">父节点</param>
        public void AddNode(ResourceInfo node, Node parentNode)
        {
            Node nd = AddResNode(node, parentNode);
            if (nd != null)
            {
                AddDataset(node, nd);
                AddRasterResource(node, nd);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="parentNode"></param>
        /// <param name="drag"></param>
        /// <returns></returns>
        private Node AddResNode(ResourceInfo node, Node parentNode, bool drag = true)
        {
            Node nd = new Node();
            nd.Name = node.ID;
            nd.Text = node.Name;
            nd.Tag = node;
            nd.DragDropEnabled = drag;
            nd.CheckBoxVisible = _ShowCheckBox;
            nd.Checked = MapControl == null ? node.GetEnable() : false;//MapControl不为空时为基础系统，默认不选中（暂时使用）
            if (parentNode == null)
            {
                this.Nodes.Add(nd);
            }
            else
            {
                parentNode.Nodes.Add(nd);
                parentNode.ExpandAll();
            }
            return nd;
        }

        /// <summary>
        /// 添加数据集、要素类到数据源节点中
        /// </summary>
        /// <param name="res"></param>
        /// <param name="parentNode"></param>
        public void AddDataset(ResourceInfo res, Node parentNode, bool reloadAll = true)
        {
            if (res.ResType != ((int)zjgisResType.GISDB).ToString()) return;
            if (string.IsNullOrWhiteSpace(res.Server) || string.IsNullOrWhiteSpace(res.Database))
            {
                return;
            }
            if (!VerifyHelper.IsNumber(res.Database))
            {
                IWorkspace wks = PlanningGIS.ArcGIS.WorkspaceHelper.OpenSDEWorkspace(res.Server, res.UserName, res.Password, res.Database);
                IEnumDatasetName dsEnumName = wks.get_DatasetNames(esriDatasetType.esriDTAny);
                dsEnumName.Reset();
                IDatasetName dsName = null;
                while ((dsName = dsEnumName.Next()) != null)
                {
                    if (dsName.Name.Contains("."))
                    {
                        string[] tmps = dsName.Name.Split('.');
                        if (!res.UserName.Equals(tmps[0], StringComparison.CurrentCultureIgnoreCase)) continue;
                    }
                    Node findNode;
                    ResourceInfo tmp = CreateResource(res, dsName);
                    if (dsName is IFeatureClassName)
                    {
                        tmp.ResType = ((int)zjgisResType.FeatureClass).ToString();
                        if (!reloadAll && ExitNode(tmp, parentNode, out findNode)) continue;
                        Node nd = AddResNode(tmp, parentNode, false);
                    }
                    else if (dsName is IFeatureDatasetName)
                    {
                        Node nd;
                        tmp.ResType = ((int)zjgisResType.Dataset).ToString();
                        if (!reloadAll && ExitNode(tmp, parentNode, out findNode))
                        {
                            nd = findNode;
                            tmp = findNode.Tag as ResourceInfo;
                        }
                        else
                        {
                            nd = AddResNode(tmp, parentNode, false);
                        }
                        IEnumDatasetName fdsnames = (dsName as IFeatureDatasetName).FeatureClassNames;
                        IDatasetName dsname2 = null;
                        while ((dsname2 = fdsnames.Next()) != null)
                        {
                            if (dsname2 is IFeatureClassName)
                            {
                                ResourceInfo tmp2 = CreateResource(tmp, dsname2);
                                tmp2.ResType = ((int)zjgisResType.FeatureClass).ToString();
                                if (!reloadAll && ExitNode(tmp2, nd, out findNode)) continue;
                                Node nd2 = AddResNode(tmp2, nd, false);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 添加栅格资源
        /// </summary>
        /// <param name="res"></param>
        /// <param name="parentNode"></param>
        /// <param name="reloadAll"></param>
        public void AddRasterResource(ResourceInfo res, Node parentNode, bool reloadAll = true)
        {
            if (res.ResType != ((int)zjgisResType.GISDB).ToString()) return;
            if (string.IsNullOrWhiteSpace(res.Server) || string.IsNullOrWhiteSpace(res.Database))
            {
                return;
            }
            IWorkspace wks = PlanningGIS.ArcGIS.WorkspaceHelper.OpenSDEWorkspace(res.Server, res.UserName, res.Password, res.Database);
            ITable table = PlanningGIS.ArcGIS.GeodatabaseHelper.OpenTable(wks, ResourceHelper.RasterInfo.TableName);
            if (table == null) return;
            Node findnode;
            Node nd;
            ResourceInfo tmp;
            tmp = CreateResource(res, "栅格数据资源", ResourceHelper.RasterInfo.TableName);
            tmp.ResType = ((int)zjgisResType.Group).ToString();
            if (!reloadAll && ExitNode(tmp, parentNode, out findnode)) 
            {
                nd = findnode;
                tmp = nd.Tag as ResourceInfo;
            }
            else
            {
                nd = AddResNode(tmp, parentNode, false);
            }
            int idxID = table.FindField(ResourceHelper.RasterInfo.ID);
            int idxName = table.FindField(ResourceHelper.RasterInfo.NAME);
            ICursor cursor = table.Search(null, false);
            IRow r = null;
            while ((r = cursor.NextRow()) != null) 
            {
                ResourceInfo tmp2 = CreateResource(tmp, r.Value[idxName].ToString(), r.Value[idxName].ToString(), r.Value[idxID].ToString());
                tmp2.ResType = ((int)zjgisResType.Raster).ToString();
                Node findNode;
                if (!reloadAll && ExitNode(tmp2, nd, out findNode)) continue;
                Node nd2 = AddResNode(tmp2, nd, false);
            }   
        }

        private bool ExitNode(ResourceInfo res, Node parentNode,out Node findNode)
        {
            findNode = null;
            if (parentNode == null || parentNode.Nodes.Count == 0) return false;
            foreach (Node child in parentNode.Nodes)
            {
                ResourceInfo nodeRes = child.Tag as ResourceInfo;
                if (nodeRes == null) continue;
                if (nodeRes.ResType == ((int)zjgisResType.Group).ToString())
                {
                    if (nodeRes.Name == res.Name)
                    {
                        findNode = child;
                        return true;
                    }
                }
                else
                {
                    if (nodeRes.DataName == res.DataName)
                    {
                        findNode = child;
                        return true;
                    } 
                }
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        private string GetAliasNameByRule(string name)
        {
            return "";
        }
        
        /// <summary>
        /// 创建资源节点
        /// </summary>
        /// <param name="parent_res"></param>
        /// <param name="datasetName"></param>
        /// <returns></returns>
        private ResourceInfo CreateResource(ResourceInfo parent_res, IDatasetName datasetName)
        {
            ResourceInfo tmp = new ResourceInfo()
            {
                ID = Guid.NewGuid().ToString(),
                Parent_ID = parent_res.ID,
                Server = parent_res.Server,
                Database = parent_res.Database,
                Name = datasetName.Name,
                UserName = parent_res.UserName,
                Password = parent_res.Password,
                DataName = datasetName.Name
            };
            tmp.SetEnable(true);
            return tmp;
        }

        /// <summary>
        /// 创建资源节点
        /// </summary>
        /// <param name="parent_res"></param>
        /// <param name="datasetName"></param>
        /// <returns></returns>
        private ResourceInfo CreateResource(ResourceInfo parent_res, string resName, string dataName, string id = null)
        {
            ResourceInfo tmp = new ResourceInfo()
            {
                ID = id == null ? Guid.NewGuid().ToString() : id ,
                Parent_ID = parent_res.ID,
                Server = parent_res.Server,
                Database = parent_res.Database,
                Name = resName,
                UserName = parent_res.UserName,
                Password = parent_res.Password,
                DataName = dataName
            };
            tmp.SetEnable(true);
            return tmp;
        }

        /// <summary>
        /// 设置角色的资源的启用状态
        /// </summary>
        /// <param name="rels"></param>
        /// <param name="nodes"></param>
        public void SetEnableAll(List<Role_Rel> rels, NodeCollection nodes)
        {
            foreach (Node nd in nodes)
            {
                if (nd.Nodes.Count > 0) SetEnableAll(rels, nd.Nodes);
                if (nd.Tag == null) continue;
                string id = ((ResourceInfo)nd.Tag).ID;
                Role_Rel r = null;
                if (rels != null)
                    r = rels.FirstOrDefault<Role_Rel>(t => t.RelID.Equals(id, StringComparison.CurrentCultureIgnoreCase));
                nd.Checked = r == null ? false : true;
            }
        }

        /// <summary>
        /// 设置所有资源的启用状态
        /// </summary>
        /// <param name="enable">是否启用</param>
        /// <param name="node">需要设置的节点</param>
        public void SetEnableAll(bool enable, Node node)
        {
            if (node == null)
            {
                SetEnableAll(enable, this.Nodes);
            }
            else
            {
                node.Checked = enable;
                ((ResourceInfo)node.Tag).SetEnable(enable);
                SetEnableAll(enable, node.Nodes);
            }
        }

        /// <summary>
        /// 启用或禁用所有功能
        /// </summary>
        /// <param name="enable">是否启用</param>
        public void SetEnableAll(bool enable, NodeCollection nodes)
        {
            if (nodes == null || nodes.Count == 0) return;
            foreach (Node nd in nodes)
            {
                if (!_IsChange && nd.Checked != enable) _IsChange = true;
                nd.Checked = enable;
                ((ResourceInfo)nd.Tag).SetEnable(enable);
                SetEnableAll(enable, nd.Nodes);
            }
        }

        /// <summary>
        /// 控制节点是否可以接收拖动
        /// </summary>
        /// <param name="e"></param>
        protected override void OnNodeDragFeedback(TreeDragFeedbackEventArgs e)
        {
            base.OnNodeDragFeedback(e);
            e.AllowDrop = false; 
            //if (e.ParentNode != null && e.ParentNode.Tag !=null)
            //{
            //    ResourceInfo res = (ResourceInfo)e.ParentNode.Tag;
            //    if (res.ResType == ((int)zjgisResType.GISDB).ToString() ||
            //        res.ResType == ((int)zjgisResType.Dataset).ToString() ||
            //        res.ResType == ((int)zjgisResType.FeatureClass).ToString() )
            //        e.AllowDrop = false;
            //}
        }

        /// <summary>
        /// 
        /// </summary>
        private Dictionary<string, IWorkspace> _OpenWorkspace = null;

        /// <summary>
        /// 加载节点数据
        /// </summary>
        public virtual void LoadData(Node node)
        {
            if (node == null || node.Tag == null  || MapControl == null) return;
            ResourceInfo res = (ResourceInfo)node.Tag;
            if (res.ResType == ((int)zjgisResType.FeatureClass).ToString())
            {
                if (node.Checked)
                    AddFeatureClass(res);
                else
                {
                    ILayer lyr = MapHelper.GetFirstLayer(MapControl.Map, res.DataName, true);
                    if (lyr != null)
                    {
                        try
                        {
                            MapControl.Map.DeleteLayer(lyr);
                        }
                        catch
                        {

                        }
                    }
                }
            }
            else if (res.ResType == ((int)zjgisResType.Raster).ToString())
            { }
            else
            {
                foreach (Node itm in node.Nodes)
                {
                    LoadData(itm);
                }
            }
            FrameworkHelper.RefreshMap();
            FrameworkHelper.RefreshToc();
        }



        /// <summary>
        /// 
        /// </summary>
        /// <param name="res"></param>
        protected void AddFeatureClass(ResourceInfo res)
        {
            if (MapControl == null || MapControl.Map == null) return;
            if (res == null || string.IsNullOrWhiteSpace(res.DataName)) return;
            ILayer existlyr = MapHelper.GetFirstLayer(MapControl.Map, res.DataName, true);
            if (existlyr != null) return;
            Log log = new Log()
            {
                USER_ID = FrameworkHelper.CurrentUser.ID,
                USER_NAME = FrameworkHelper.CurrentUser.Name,
                OP_TYPE = PlanningGIS.ManageUtility.Modules.zjgisLogType.AccessData,
                DATA_INVOLOVE = string.Format("访问的数据为{0} {1}中的{2}", res.Server, res.Database, res.DataName),
                NOTES = "申请访问数据，但由于数据原因，导致数据访问失败",
                OP_STATUS = zjgisLogStatus.Fail,
            };
            try
            {
                IWorkspace wks = GetWorkspace(res);
                if (wks == null) return;
                IFeatureClass featcls = GeodatabaseHelper.OpenFeatureClass(wks, res.DataName);
                if (featcls == null) return;
                IFeatureLayer lyr = new FeatureLayer();
                lyr.FeatureClass = featcls;
                lyr.Name = res.Name;
                if (res.MaxScale - res.MinScale < 0)
                {
                    lyr.MinimumScale = res.MinScale;
                    lyr.MaximumScale = res.MaxScale;
                }
                MapControl.AddLayer(lyr);
                log.NOTES = string.Format("申请访问数据，数据在{0}时加载完成。", DateTime.Now.ToString());
                log.OP_STATUS = zjgisLogStatus.Success;
            }
            catch (Exception ex)
            {
                log.REMARK = DateTime.Now.ToString() + ex.Message;
            }
            finally
            {
                Log.WriteLog(log);
            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="res"></param>
        /// <returns></returns>
        private IWorkspace GetWorkspace(ResourceInfo res)
        {
            if (_OpenWorkspace == null) _OpenWorkspace = new Dictionary<string, IWorkspace>();
            string key = (res.Server + "_" + res.UserName).ToLower().Trim();
            if (_OpenWorkspace.ContainsKey(key)) return _OpenWorkspace[key];
            try
            {
                IWorkspace wks = PlanningGIS.ArcGIS.WorkspaceHelper.OpenSDEWorkspace(res.Server, res.UserName, res.Password, res.Database);
                _OpenWorkspace.Add(key, wks);
                return wks;
            }
            catch (Exception ex)
            {
                MsgHelper.ShowErrorMsgbox(ex.Message);
                return null;
            }
            
        }
    }
}
